#!/usr/bin/env ruby

## The MIT License (MIT)
##
## Copyright (c) 2018 SavinMax. All rights reserved.
##
## Permission is hereby granted, free of charge, to any person obtaining a copy
## of this software and associated documentation files (the "Software"), to deal
## in the Software without restriction, including without limitation the rights
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## copies of the Software, and to permit persons to whom the Software is
## furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in
## all copies or substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
## THE SOFTWARE.

require "yaml"
require "./tools/utils"

defines = Utils.all_structs
msg_defines = Utils.msg_structs

PROTOCOL_TYPE = defines.keys

package = "pbapi"
proto_dir = "../src/goslib/gen/api/#{package}"
`mkdir -p #{proto_dir}`

header = %Q{\
/*
 * Generated by tools/gen_protocol_pb
 */
}

encode_handlers = []
decode_handlers = []

defines.each do |protocol, define|
  decode_handlers << %Q{
func decode#{protocol}(buffer *packet.Packet) (interface{}, error) {
    data := &pt.#{protocol}{}
    err := proto.Unmarshal(buffer.RemainData(), data)    
    return data, err
}}
  encode_handlers << %Q{
func encode#{protocol}(buffer *packet.Packet, value interface{}) error {
    data, err := proto.Marshal(value.(*pt.#{protocol}))
    buffer.WriteRawBytes(data)
    return err
}}
end

#
# Generate api decoder
#

target = "#{proto_dir}/decoder.go"
File.open(target, "w") do |io|
  io.write %Q{\
#{header}
package #{package}

import (
    "github.com/mafei198/gos/goslib/gen/api/pt"
    "github.com/golang/protobuf/proto"
	"github.com/mafei198/gos/goslib/packet"
)

#{decode_handlers.join("\n")}

type DecodeHandler func(buffer *packet.Packet) (interface{}, error)

var decode_handlers = map[string]DecodeHandler{
    #{defines.keys.map{|protocol| "\"#{protocol}\": decode#{protocol}"}.join(",\n    ")}}

func Decode(decode_method string, buffer *packet.Packet) (interface{}, error) {
	if handler, ok := decode_handlers[decode_method]; ok {
		return handler(buffer)
	} else {
		return nil, nil
	}
}
}
end
`gofmt -w #{target}`

#
# Generate api encoder
#
target = "#{proto_dir}/encoder.go"
File.open(target, "w") do |io|
  io.write %Q{\
#{header}
package #{package}

import (
	"fmt"
	"reflect"
	"errors"
	"github.com/mafei198/gos/goslib/gen/api/pt"
    "github.com/golang/protobuf/proto"
  	"github.com/mafei198/gos/goslib/packet"
)

#{encode_handlers.join("\n")}

type EncodeHandler func(buffer *packet.Packet, value interface{}) error
func Encode(v interface{}) (*packet.Packet, error) {
	encode_method, handler := EncodeMethod(v)
    if handler == nil {
        errMsg := fmt.Sprintf("no encode handle: %s", reflect.TypeOf(v).String())
		return nil, errors.New(errMsg)
    }
	protocol := pt.NameToId[encode_method]
	buffer := packet.Writer()
	buffer.WriteUint16(protocol)
	err := handler(buffer, v)
    return buffer, err
}
func EncodeMethod(v interface{}) (string, EncodeHandler) {
	switch v.(type) {
    #{msg_defines.keys.map{|protocol| "case *pt.#{protocol}: return pt.PT_#{protocol}, encode#{protocol}"}.join("\n    ")}
	}
	return "", nil
}
}
end
`gofmt -w #{target}`
